package swistak.service;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.Resource;
import org.springframework.transaction.annotation.Transactional;

import swistak.domain.Client;

//@Transactional
public class ClientDAOImpl implements ClientDAO {

	private static final String SEPARATOR_LINE = "@@###&&###@@";
	
	protected final Log logger = LogFactory.getLog(getClass());

	private Resource file;

	@PersistenceContext
	private EntityManager em;
	
	private ClientDAO clientDAO;
	
	public void setClientDAO(ClientDAO clientDAO) {
		this.clientDAO = clientDAO;
	}

	public void init(){
//		clientDAO.readDataFromFile();
	}

//	@Transactional
	public void readDataFromFile() {
//		ResourceLoader appCtx = new ClassPathXmlApplicationContext(
//				"../swistak-servlet.xml");
		logger.info("readDataFromFile");
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(file.getFile()));
			readFileContent(reader);
		} catch (FileNotFoundException e) {
			throw new SwistakException(e);
		} catch (IOException e) {
			throw new SwistakException(e);
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
					throw new SwistakException(e);
				}
			}
		}
	}
	
	@Transactional
	@SuppressWarnings("unchecked")
	public List<Client> findAll(){
		Query q = em.createNamedQuery(Client.NQ_FIND_ALL);
		return q.getResultList();
	}

	private void readFileContent(BufferedReader reader) throws IOException {
		String nameLine, addrLine, cityLine, nipLine, sepLine;
		while ((nameLine = reader.readLine()) != null) {
			addrLine = readTrimmedLine(reader);
			cityLine = readTrimmedLine(reader);
			nipLine = readTrimmedLine(reader);
			sepLine = readTrimmedLine(reader);
			logger.info(nameLine + ", " + cityLine + ", " + nipLine);
			if (!SEPARATOR_LINE.equals(sepLine)) {
				throw new SwistakException("Wrong separator line for "
						+ nameLine);
			}
			Client client = new Client();
			client.setName(nameLine);
			client.setAddress(addrLine);
			String[] citySplit = cityLine.split(" ");
			client.setCode(citySplit[0]);
			client.setCity(citySplit[1]);
			String nip = extractNip(nipLine);
			client.setNip(nip);
			store(client);
		}
	}
	
	@Transactional
	public void store(Client c){
		em.merge(c);
	}
	
	private String extractNip(String line) {
		Pattern p = Pattern.compile("\\d+");
		Matcher m = p.matcher(line);
		String parts = "";
		while (m.find()) {
			parts += m.group();
		}
		if (parts.length() != 10) {
			throw new SwistakException("Unable to extract NIP from " + line);
		}
		return parts.substring(0, 3) + "-" + parts.substring(3, 6) + "-"
				+ parts.substring(6, 8) + "-" + parts.substring(8);
	}

	private String readTrimmedLine(BufferedReader reader) throws IOException {
		return reader.readLine().trim();
	}

	public void setFile(Resource file) {
		this.file = file;
	}

	@Override
	public void deleteAll() {
		Query q = em.createNamedQuery(Client.NQ_DELETE_ALL);
		q.executeUpdate();
	}

	@Transactional
	@Override
	public void delete(long id) {
		em.remove(find(id));
	}

	@Override
	public void addFromFile() {
		
		
	}

	@Transactional
	@Override
	public Client find(long id) {
		return em.find(Client.class, id);
	}
	
}
